﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Windows;
using GoearAPI;
using Growl.CoreLibrary;
using Growl.Connector;
using SimpleConfig;
namespace GEDownloader
{
    /// <summary>
    /// Partial class frmMain. Main application form.
    /// </summary>
    public partial class frmMain : Form
    {
        public static Boolean __DEBUG = false;
        #region Literal String Constants
            private String MSG_PROCESS_ABORTED = "Proceso abortado";
            private String MSG_PROCESS_COMPLETE = "Proceso completo";
            private String MSG_DOWNLOAD_COMPLETE = "Descarga completa";
            private String MSG_CONFIRM_EXIT = "Hay descargas en proceso. Desea salir?";
            private String MSG_TITLE_EXIT = "Salir del programa";
            private String MSG_TITLE_DOWNLOAD_STARTED = "Inicio de descarga";
            private String MSG_ERROR_DOWNLOADING = "Error al iniciar la descarga.";
            private String MSG_ERROR_URL_WRONG = "URL incorrecta.";
            private String MSG_ERROR_URL_EMPTY = "URL vacía.";
            private String MSG_PARTIAL_X_OF_Y = " de ";
            private String MSG_PARTIAL_FROM = " desde ";
            private String MSG_PARTIAL_FROM_FILE = " del archivo";
            private String MSG_PARTIAL_ITEM_1 = "Item 1: ";
            private String MSG_PARTIAL_ITEM = "Item ";
            private String MSG_PARTIAL_DOWNLOADED = "Descargados ";
            private String MSG_PARTIAL_ELEMENTS = " elementos";
            private String MSG_PARTIAL_ITEM_1_DOWNLOADED = "Item 1: Descargando  ";
            private String MSG_PARTIAL_DOWNLOADING_ITEM = "Descargando elemento ";
            private String MSG_PARTIAL_DOWNLOADING = "Descargando: ";
            private String MSG_PARTIAL_DONE = "Listo!";
            private String MSG_PARTIAL_COMPLETED = " completado.";
            private String MSG_NO_OUTPUT_DIR = "No has especificado dónde guardar las canciones";
            private String MSG_NO_SONGS_TO_DOWNLOAD = "No hay canciones que descargar";
            private String MSG_PROCESS_RUNNING = "Ya está ejecutando un proceso";
            private String LBL_HELP_HEADER = "Entra en Goear.com y busca las canciones que quieras." + 
                "\r\nLuego copia las URL en la lista de abajo y descárgalas.";
            private String LBL_URL_LIST = "Lista de URLs";
            private String LBL_OUTPUT_DIR = "Carpeta de salida";
            private String LBL_LOG_BOX = "Log del proceso";
            private String LBL_START_BUTTON = "Iniciar proceso";
            private String LBL_CANCEL_BUTTON = "Cancelar proceso";
            private String LBL_EXIT_BUTTON = "Salir";
            public static String LBL_ABOUT_FORM_CLOSE_WINDOW = "Cerrar ventana";
            public static String LBL_ABOUT_FORM_DESCRIPTION = "Descripción de GEDownloader";
            public static String LBL_ABOUT_GOEAR_DISCLAIMER = "Visita goear.com y consigue las URL de tus canciones favoritas allí." + 
                CRLF + "¡Todos ganamos!";



            private static String CRLF = "\r\n";
        #endregion

        #region GoearAPI class constants and variables
            private const String ERR_EMPTY_LINE = "ERR_EMPTY_LINE";
            private const String ERR_WRONG_URL = "ERR_WRONG_URL";
            private const String ERR_NO_XML = "ERR_NO_XML";
            protected GoearAPI.GoearAPI geApiHandler;
        #endregion

        #region Growl variables
            private GrowlConnector growl = null;
            private NotificationType gNotDownloadComplete = new NotificationType("D_COMPLETE", "Download complete");
            private NotificationType gNotProcessComplete = new NotificationType("P_COMPLETE", "Process complete");
            private NotificationType gNotProcessAborted = new NotificationType("P_ABORTED", "Process aborted");
            private NotificationType gNotProcessStarted = new NotificationType("P_STARTED", "Process started");
            private NotificationType gNotDownloadStarted = new NotificationType("D_STARTED", "Download started");
            private NotificationType gNotProcessAlreadyRunning = new NotificationType("P_ALREADY_RUNNING", "Process already running");
            private NotificationType gNotErrorEmptyList = new NotificationType("E_EMPTY_LIST", "No songs to download");
            private NotificationType gNotErrorWrongURL = new NotificationType("E_WRONG_URL", "Wrong URL");
            private NotificationType gNotErrorFailedConnection = new NotificationType("E_FAILED_CONNECTION", "Failed connection");
            private NotificationType gNotErrorWrongOutputDir = new NotificationType("E_WRONG_OUTPUT_DIR", "Wrong output folder");
            private String notificationTitle = "";
            private String notificationMessage = "";
            protected Boolean hasGrowl;
        #endregion

        #region class variables
            private String DEFAULT_LANGUAGE = "spanish";
            protected WebClient wcDownloader;
            protected Boolean abort;
            protected Boolean running;
            protected int currentFile;
        #endregion

            public SimpleConf Config;


        #region Constructor
        /// <summary>
        /// frmMain Constructor
        /// </summary>
        public frmMain() {
            InitializeComponent();

            /*
             * First of all, we try to set up a Growl handler.
             * If it fails, we set the HasGrowl flag to false.
             * The notification methods and events should check this flag.
             */
            try
            {
                //Our application must be registered at the begininng. We give the name and an icon to show.
                growl = new GrowlConnector();
                Growl.Connector.Application application = new Growl.Connector.Application("GEDownloader");
                application.Icon = @System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + @"\goearmini.ico";
                
                //Also, we pass all the NotificationType elements we declared above.
                growl.Register(application, new NotificationType[] { 
                gNotDownloadComplete,
                gNotProcessComplete,
                gNotProcessAborted,
                gNotProcessStarted,
                gNotProcessAlreadyRunning,
                gNotErrorEmptyList,
                gNotDownloadStarted,
                gNotErrorWrongURL,
                gNotErrorWrongOutputDir,
                gNotErrorFailedConnection
            });
                //Next, we set up an event handler for the Growl responses. Basicly, to handle errors.
                growl.ErrorResponse += new GrowlConnector.ResponseEventHandler(growl_ErrorResponse);
                this.hasGrowl = true;
            }
            catch (GrowlException ex) {
                this.hasGrowl = false;
            }
            
            //Invoking the GoearAPI handler, the webClient handler and eventHandlers for both of them
            geApiHandler = new GoearAPI.GoearAPI();
            this.wcDownloader = new System.Net.WebClient();
            wcDownloader.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
            wcDownloader.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
            
            //initial values for process flags
            this.abort = false;
            this.running = false;
            this.currentFile = 0;

            this.Config = new SimpleConf();
            this.Config.openConfigHandler(System.IO.Directory.GetCurrentDirectory()+@"\config.xml");
        }
        #endregion

        #region Support methods

        /// <summary>
        /// Reloads the Config object, to avoid problems with updated values
        /// </summary>
        public void reloadConfig() {
            this.Config = null;
            this.Config = new SimpleConf();
            this.Config.openConfigHandler(System.IO.Directory.GetCurrentDirectory() + @"\config.xml");
            if (this.Config.readBoolean("use_proxy", "proxy"))
            {
                geApiHandler.useProxy(
                    this.Config.readString("type", "proxy"),
                    this.Config.readString("hostname", "proxy"),
                    this.Config.readInteger("port", "proxy"),
                    this.Config.readString("username", "proxy"),
                    this.Config.readString("password", "proxy")
                    );
            }
            else
            {
                geApiHandler.dontUseProxy();
            }
        }

        /// <summary>
        /// Reset the two progress bars
        /// </summary>
        private void resetProgressBars()
        {
            progressUnit.Maximum = 100;
            progressUnit.Minimum = 0;
            progressUnit.Value = 0;
            progressBatch.Maximum = txtInputList.Lines.Count();
            progressBatch.Minimum = 0;
            progressBatch.Value = 0;
        }

        /// <summary>
        /// Reset the two progress bars, the buttons and boxes, 
        /// the file counter and the abort and running flags
        /// </summary>
        private void resetItems()
        {
            btnStart.Enabled = true;
            txtInputList.Enabled = true;
            txtOutputDir.Enabled = true;
            this.resetProgressBars();
            this.running = false;
            return;
        }

        /// <summary>
        /// Shows a BalloonMessage on the tray system icon.
        /// </summary>
        /// <param name="title">Balloon Message title</param>
        /// <param name="message">Balloon Message text</param>
        /// <param name="milliseconds">Duration in milliseconds of the Balloon Message</param>
        /// <param name="icon">Balloon Message icon. Default = Info</param>
        private void showBalloonMessage(String title, String message, int milliseconds, 
            ToolTipIcon icon = ToolTipIcon.Info) {
            trayIcon.ShowBalloonTip(milliseconds, title, message, icon);
            return;
        }

        /// <summary>
        /// Sends a notification, selecting growl if available or balloon if no Growl.
        /// </summary>
        /// <param name="type">Growl.NotificationType</param>
        /// <param name="title">Notification title</param>
        /// <param name="message">Notification message</param>
        private void showNotification(NotificationType type, String title, String message) {
            if (this.hasGrowl) {
                this.notificationTitle = title;
                this.notificationMessage = message;
                growl.Notify(new Notification("GEDownloader", type.Name.ToString(), null, title, message));
            }
            else {
                this.showBalloonMessage(title, message, 1000);
            }
        }

        /// <summary>
        /// Changes all the strings to the selected language.
        /// </summary>
        /// <param name="newLanguage">Language to switch</param>
        private void changeAppLanguage(String newLanguage) {
            if (newLanguage == "english") {
                MSG_PROCESS_ABORTED = "Process aborted";
                MSG_PROCESS_COMPLETE = "Process completed";
                MSG_DOWNLOAD_COMPLETE = "Download completed";
                MSG_CONFIRM_EXIT = "There are downloads in progress. Really exit?";
                MSG_TITLE_EXIT = "Exit the program";
                MSG_TITLE_DOWNLOAD_STARTED = "Download start";
                MSG_ERROR_DOWNLOADING = "Error starting download.";
                MSG_ERROR_URL_WRONG = "Wrong URL.";
                MSG_ERROR_URL_EMPTY = "Empty URL.";
                MSG_PARTIAL_X_OF_Y = " of ";
                MSG_PARTIAL_FROM = " from ";
                MSG_PARTIAL_FROM_FILE = " of file";
                MSG_PARTIAL_ITEM_1 = "Item 1: ";
                MSG_PARTIAL_ITEM = "Item ";
                MSG_PARTIAL_DOWNLOADED = "Downloaded ";
                MSG_PARTIAL_ELEMENTS = " items";
                MSG_PARTIAL_ITEM_1_DOWNLOADED = "Item 1: Downloading  ";
                MSG_PARTIAL_DOWNLOADING_ITEM = "Downloading item ";
                MSG_PARTIAL_DOWNLOADING = "Downloading: ";
                MSG_PARTIAL_DONE = "Completed!";
                MSG_PARTIAL_COMPLETED = " completed.";
                MSG_NO_OUTPUT_DIR = "Output directory not specified!";
                MSG_NO_SONGS_TO_DOWNLOAD = "No songs to download";
                MSG_PROCESS_RUNNING = "Process already running";

                LBL_HELP_HEADER = "Go to Goear.com search the songs you want." +
                "\r\nThen copy the URLs in the list below and download them!";
                LBL_URL_LIST = "Song URL List";
                LBL_OUTPUT_DIR = "Output folder";
                LBL_LOG_BOX = "Process log";
                LBL_START_BUTTON = "Start process";
                LBL_CANCEL_BUTTON = "Cancel process";
                LBL_EXIT_BUTTON = "Exit";
                LBL_ABOUT_FORM_CLOSE_WINDOW = "Close this window";
                LBL_ABOUT_FORM_DESCRIPTION = "GEDownloader is a Goear.com song downloader with cue list support.";
                LBL_ABOUT_GOEAR_DISCLAIMER = "Support goear.com getting your favourites songs URL from their site." +
                CRLF + "¡We all win!";
            }
            if (newLanguage == "spanish") {
                MSG_PROCESS_ABORTED = "Proceso abortado";
                MSG_PROCESS_COMPLETE = "Proceso completo";
                MSG_DOWNLOAD_COMPLETE = "Descarga completa";
                MSG_CONFIRM_EXIT = "Hay descargas en proceso. Desea salir?";
                MSG_TITLE_EXIT = "Salir del programa";
                MSG_TITLE_DOWNLOAD_STARTED = "Inicio de descarga";
                MSG_ERROR_DOWNLOADING = "Error al iniciar la descarga.";
                MSG_ERROR_URL_WRONG = "URL incorrecta.";
                MSG_ERROR_URL_EMPTY = "URL vacía.";
                MSG_PARTIAL_X_OF_Y = " de ";
                MSG_PARTIAL_FROM = " desde ";
                MSG_PARTIAL_FROM_FILE = " del archivo";
                MSG_PARTIAL_ITEM_1 = "Item 1: ";
                MSG_PARTIAL_ITEM = "Item ";
                MSG_PARTIAL_DOWNLOADED = "Descargados ";
                MSG_PARTIAL_ELEMENTS = " elementos";
                MSG_PARTIAL_ITEM_1_DOWNLOADED = "Item 1: Descargando  ";
                MSG_PARTIAL_DOWNLOADING_ITEM = "Descargando elemento ";
                MSG_PARTIAL_DOWNLOADING = "Descargando: ";
                MSG_PARTIAL_DONE = "Listo!";
                MSG_PARTIAL_COMPLETED = " completado.";
                MSG_NO_OUTPUT_DIR = "No has especificado dónde guardar las canciones";
                MSG_NO_SONGS_TO_DOWNLOAD = "No hay canciones que descargar";
                MSG_PROCESS_RUNNING = "Ya está ejecutando un proceso";

                LBL_HELP_HEADER = "Entra en Goear.com y busca las canciones que quieras." +
                "\r\nLuego copia las URL en la lista de abajo y descárgalas.";
                LBL_URL_LIST = "Lista de URLs";
                LBL_OUTPUT_DIR = "Carpeta de salida";
                LBL_LOG_BOX = "Log del proceso";
                LBL_START_BUTTON = "Iniciar proceso";
                LBL_CANCEL_BUTTON = "Cancelar proceso";
                LBL_EXIT_BUTTON = "Salir";
                LBL_ABOUT_FORM_CLOSE_WINDOW = "Cerrar esta ventana";
                LBL_ABOUT_FORM_DESCRIPTION = "GEDownloader es un sistema de descarga de canciones de goear.com con soporte para descargas múltiples.";
                LBL_ABOUT_GOEAR_DISCLAIMER = "Visita goear.com y consigue las URL de tus canciones favoritas allí." +
                CRLF + "¡Todos ganamos!";
            }
            lblHelpHeader.Text = LBL_HELP_HEADER;
            lblInputList.Text = LBL_URL_LIST;
            lblOutputDir.Text = LBL_OUTPUT_DIR;
            lblProcessLog.Text = LBL_LOG_BOX;
            btnStart.Text = LBL_START_BUTTON;
            btnCancel.Text = LBL_CANCEL_BUTTON;
            btnExit.Text = LBL_EXIT_BUTTON;
        }

        /// <summary>
        /// Generates a full path + filename to download the song, dealing with already existent files
        /// </summary>
        /// <param name="filePath">The path without filename</param>
        /// <param name="fileTitle">The filename, without extension</param>
        /// <param name="fileExtension">The file extension ".xxx"</param>
        /// <returns>A free path + filename</returns>
        private String fileNameHash(String filePath, String fileTitle, String fileExtension)
        {
            String return_path = String.Concat(filePath, "\\", fileTitle, fileExtension);
            String randomHash = "";
            if (File.Exists(filePath + "\\" + fileTitle + fileExtension))
            {
                while (File.Exists(filePath + "\\" + fileTitle +
                                        "_" + randomHash + "_" + fileExtension))
                {
                    randomHash = DateTime.Now.Millisecond.ToString();
                }
                return_path = filePath + "\\" + fileTitle + "_" + randomHash + "_" + fileExtension;
            }

            return return_path;
        }
        
        #endregion

        #region Events
            #region Manual events
        /// <summary>
        /// Handles the progressChanged event of the webclient control
        /// </summary>
        /// <param name="sender">Standard sender param</param>
        /// <param name="e">DownloadProgressChangedEventArgs e param </param>
        private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            progressUnit.Value = e.ProgressPercentage;
            lblUnitaryProgress.Text = e.ProgressPercentage + "%" + MSG_PARTIAL_FROM_FILE;
            if (this.abort && this.running)
            {
                //wcDownloader.CancelAsync();
                this.Completed(sender,new AsyncCompletedEventArgs(new Exception("Cancel signal received"),true,null));
                lblTotalProgress.Text = progressBatch.Value.ToString() + MSG_PARTIAL_X_OF_Y + txtInputList.Lines.Length.ToString();
            }
            progressBatch.Update();
            progressUnit.Update();
        }

        /// <summary>
        /// Handles the completed file download event of the webclient control
        /// </summary>
        /// <param name="sender">Standard sender param</param>
        /// <param name="e">AsyncCompletedEventArgs e param </param>
        private void Completed(object sender, AsyncCompletedEventArgs e)
        {

            if (e.Cancelled)
            {
                /* if the abort flag is set to true, we must set the running flag to false */
                this.abort = true;
                this.currentFile = txtInputList.Lines.Count();
                this.running = false;
                this.resetItems();
                this.currentFile = 0;

            }
            else {
                /* Balloon notification for completed item download */
                txtLog.Text += MSG_PARTIAL_DONE + CRLF;
                this.showNotification(
                    gNotDownloadComplete,
                    MSG_DOWNLOAD_COMPLETE,
                    MSG_PARTIAL_ITEM + (currentFile + 1).ToString() + MSG_PARTIAL_X_OF_Y +
                    progressBatch.Maximum + MSG_PARTIAL_COMPLETED);

                /* Increment of the currentFile counter and thus, the total progress bar */
                this.currentFile++;
                progressBatch.Value++;
                lblTotalProgress.Text = progressBatch.Value.ToString() + MSG_PARTIAL_X_OF_Y +
                    txtInputList.Lines.Length.ToString();
                if (this.currentFile >= txtInputList.Lines.Count())
                {
                    /* main process finished if abort flag is not set. Send notification */
                    if (!abort)
                    {
                        this.showNotification(
                            gNotProcessComplete,
                            MSG_PROCESS_COMPLETE,
                            MSG_PARTIAL_DOWNLOADED + (currentFile).ToString() +
                            MSG_PARTIAL_X_OF_Y + progressBatch.Maximum + MSG_PARTIAL_ELEMENTS);
                    }
                    this.resetItems();
                    progressUnit.Update();
                }
                else
                {
                    geApiHandler.OutputDir = txtOutputDir.Text;
                    progressUnit.Maximum = 100;
                    progressUnit.Minimum = 0;
                    progressUnit.Value = 0;
                    List<String> songDetails = geApiHandler.getFile(txtInputList.Lines[this.currentFile]);
                    switch (songDetails[0])
                    {
                        case ERR_EMPTY_LINE:
                            txtLog.Text += MSG_PARTIAL_ITEM + (currentFile + 1) + ": " + MSG_ERROR_URL_EMPTY + CRLF;
                            this.Completed(sender, new AsyncCompletedEventArgs(null,false,null));
                            break;
                        case ERR_WRONG_URL:
                            txtLog.Text += MSG_PARTIAL_ITEM + (currentFile + 1) + ": " + MSG_ERROR_URL_WRONG + CRLF;
                            this.Completed(sender, new AsyncCompletedEventArgs(null, false, null));
                            break;
                        case ERR_NO_XML:
                            txtLog.Text += MSG_PARTIAL_ITEM + (currentFile + 1) + ":" + MSG_ERROR_DOWNLOADING + CRLF;
                            this.Completed(sender, new AsyncCompletedEventArgs(null, false, null));
                            break;
                        default:
                            String finalPath = fileNameHash(txtOutputDir.Text, songDetails[1], ".mp3");
                            wcDownloader.DownloadFileAsync(new Uri(songDetails[0]), finalPath);
                            //wcDownloader.DownloadFileAsync(new Uri(songDetails[0]), songDetails[1]);
                            this.showNotification(
                            gNotDownloadStarted,
                            MSG_TITLE_DOWNLOAD_STARTED,
                            MSG_PARTIAL_DOWNLOADING_ITEM + (currentFile + 1).ToString() +
                                MSG_PARTIAL_X_OF_Y + progressBatch.Maximum);
                            txtLog.AppendText(MSG_PARTIAL_ITEM + (currentFile + 1) + ": " + MSG_PARTIAL_DOWNLOADING + ": " +
                                finalPath + MSG_PARTIAL_FROM + songDetails[0] + CRLF);
                            break;
                    }
                }
            }
          
        }

        /// <summary>
        /// Event Handler for Growl Responses
        /// </summary>
        /// <param name="response">Growl Response</param>
        /// <param name="state">Required param</param>
        private void growl_ErrorResponse(Response response, Object state) {
            /**
             *If growl returns an error status or a timeout happens and the message
             *is stored in the globals, we send the messages using the balloon system
             */
            if (this.hasGrowl && response.IsError && this.notificationMessage != "" && this.notificationTitle != "") {
                this.showBalloonMessage(this.notificationTitle, this.notificationMessage, 1000);
                this.notificationTitle = "";
                this.notificationMessage = "";
            }
        }

        #endregion

            #region Automatic events
        private void frmMain_Load(object sender, EventArgs e)
        {
            this.changeAppLanguage(DEFAULT_LANGUAGE);
            this.txtOutputDir_TextChanged(sender, e);

            if (this.Config.readBoolean("use_proxy", "proxy"))
            {
                geApiHandler.useProxy(
                    this.Config.readString("type", "proxy"),
                    this.Config.readString("hostname", "proxy"),
                    this.Config.readInteger("port", "proxy"),
                    this.Config.readString("username", "proxy"),
                    this.Config.readString("password", "proxy")
                    );
            }
            else { 
               geApiHandler.dontUseProxy();
            }

            if (__DEBUG)
            {
                
                txtLog.Text += String.Concat(CRLF, "Proxy Settings:", CRLF);
                txtLog.Text += String.Concat("Use proxy: ", this.Config.readString("use_proxy", "proxy"), CRLF);
                txtLog.Text += String.Concat("Type: ", this.Config.readString("type", "proxy"), CRLF);
                txtLog.Text += String.Concat("String: ", this.Config.readString("username", "proxy"), ":");
                txtLog.Text += String.Concat(this.Config.readString("password", "proxy"), "@");
                txtLog.Text += String.Concat(this.Config.readString("hostname", "proxy"), ":",
                                                this.Config.readString("port", "proxy"), CRLF);
            }else{
                //comment the line below, to get a three elements real list to debug
                txtInputList.Text = ""; 
            }
        }
       
        private void btnStart_Click(object sender, EventArgs e) {
            if (this.running) {
                this.showNotification(gNotProcessAlreadyRunning, MSG_PROCESS_RUNNING, MSG_PROCESS_RUNNING);
                return;
            }
            if (txtInputList.Lines.Length == 0) {
                this.showNotification(gNotErrorEmptyList, MSG_NO_SONGS_TO_DOWNLOAD, MSG_NO_SONGS_TO_DOWNLOAD);
                this.running = false;
                return;
            }
            if (txtOutputDir.Text.Trim() == "") {
                this.showNotification(gNotErrorWrongOutputDir, MSG_NO_OUTPUT_DIR, MSG_NO_OUTPUT_DIR);
                this.running = false;
                return;
            }
            this.resetProgressBars();
            btnStart.Enabled = false;
            txtInputList.Enabled = false;
            txtOutputDir.Enabled = false;
            geApiHandler.OutputDir = txtOutputDir.Text;
            this.currentFile = 0;
            if ((txtInputList.Lines[txtInputList.Lines.Length - 1]).Trim().Equals("")) {
                txtInputList.Text.TrimEnd(CRLF.ToCharArray());
            }
            List<String> songDetails = geApiHandler.getFile(txtInputList.Lines[0]);
            switch (songDetails[0])
            {
                case ERR_EMPTY_LINE:
                    txtLog.Text += MSG_PARTIAL_ITEM_1 + MSG_ERROR_URL_EMPTY + CRLF;
                    this.Completed(sender,
                    new AsyncCompletedEventArgs(new Exception("Empty line"), true, null));
                break;
                case ERR_WRONG_URL:
                    txtLog.Text += MSG_PARTIAL_ITEM_1 + MSG_ERROR_URL_WRONG + CRLF;
                    this.Completed(sender, new AsyncCompletedEventArgs(new Exception("Wrong URL"), true, null));
                break;
                case ERR_NO_XML:
                    txtLog.Text += MSG_PARTIAL_ITEM_1 + MSG_ERROR_DOWNLOADING + CRLF;
                    this.Completed(sender, new AsyncCompletedEventArgs(new Exception("Cannot connect to tracker"), true, null));
                break;
                default:

                if (this.Config.readBoolean("use_proxy", "proxy"))
                {
                    WebProxy wp = new WebProxy(
                        this.Config.readString("hostname","proxy") + ":" +
                this.Config.readString("port", "proxy")
                );
                    wp.Credentials = new NetworkCredential(
                        this.Config.readString("username", "proxy"),
                        this.Config.readString("password", "proxy")
                        );
                    wcDownloader.Proxy = wp;
                }
                if (__DEBUG) {
                    txtLog.Text += String.Concat(CRLF,"Proxy Settings:",CRLF);
                    txtLog.Text += String.Concat("Use proxy: ", this.Config.readString("use_proxy", "proxy"), CRLF);
                    txtLog.Text += String.Concat("Type: ",this.Config.readString("type", "proxy"), CRLF);
                    txtLog.Text += String.Concat("String: ",this.Config.readString("username", "proxy"), ":");
                    txtLog.Text += String.Concat(this.Config.readString("password", "proxy"), "@");
                    txtLog.Text += String.Concat(this.Config.readString("hostname", "proxy"), ":", 
                                                    this.Config.readString("port", "proxy"),CRLF);
                }
                String finalPath = fileNameHash(txtOutputDir.Text, songDetails[1], ".mp3");
                wcDownloader.DownloadFileAsync(new Uri(songDetails[0]), finalPath);
                    this.showNotification(gNotDownloadStarted, MSG_TITLE_DOWNLOAD_STARTED,
                        MSG_PARTIAL_DOWNLOADING_ITEM + (currentFile + 1).ToString() +
                        MSG_PARTIAL_X_OF_Y + progressBatch.Maximum);
                    txtLog.Text += MSG_PARTIAL_ITEM_1_DOWNLOADED + finalPath 
                        + MSG_PARTIAL_FROM + songDetails[0] + CRLF;
                    this.running = true;
                break;
            }
            return;

        }

        private void btnExit_Click(object sender, EventArgs e) {
            if (!running
                || (running && MessageBox.Show(MSG_CONFIRM_EXIT, MSG_TITLE_EXIT, MessageBoxButtons.OKCancel, 
                                                MessageBoxIcon.Warning) == DialogResult.OK)) {
                    System.Windows.Forms.Application.Exit();
            }   
        }

        private void btnCancel_Click(object sender, EventArgs e) {
            this.resetItems();
            this.abort = true;
            this.running = false;
            wcDownloader.CancelAsync();
            this.showNotification(gNotProcessAborted, MSG_PROCESS_ABORTED, MSG_PROCESS_ABORTED);
        }

        private void btnBrowseDir_Click(object sender, EventArgs e) {
            if (folderBrowser.ShowDialog().Equals(DialogResult.OK)) {
                txtOutputDir.Text = folderBrowser.SelectedPath;
            }
        }

        private void txtOutputDir_TextChanged(object sender, EventArgs e) {
            if (Directory.Exists(txtOutputDir.Text)) {
                txtOutputDir.BackColor = Color.LightGreen;
            }
            else {
                txtOutputDir.BackColor = Color.LightCoral;
            }
        }

        private void trayIcon_MouseDoubleClick(object sender, MouseEventArgs e) {
            if (this.Visible)
                this.Hide();
            else
                this.Show();
        }

        private void btnAbout_Click(object sender, EventArgs e)
        {
            (new AboutFormGE()).ShowDialog();
        }

        private void lblHelpHeader_Click(object sender, EventArgs e)
        {
            Process.Start("http://www.goear.com");
        }

        private void btnOptions_Click(object sender, EventArgs e)
        {
            
            (new frmOptions(this)).ShowDialog();
        }
        #endregion

        private void txtInputList_DragDrop(object sender, DragEventArgs e)
        {
            try
            {
                txtInputList.Text += e.Data.GetData(DataFormats.UnicodeText).ToString() + CRLF;
            }
            catch {
                this.showNotification(this.gNotErrorWrongURL, MSG_ERROR_URL_WRONG, MSG_ERROR_URL_WRONG);
            }
        }


        #endregion

        private void txtInputList_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Link;
        }

    }
}
